package com.zzvcom.office.services;


import com.zzvcom.office.entities.OfficeFile;
import com.zzvcom.office.entities.OfficePdf;
import com.zzvcom.util.ChunkDownloader;
import com.zzvcom.util.FileItem;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 本地缓存服务
 */
@Component
@Slf4j
public class WopiLocalCacheService {
    @Autowired
    private OfficeFileServices officeFileServices;
    @Autowired
    private OfficePdfServices officePdfServices;
    /**
     * 主的下载服务
     */
    private final ExecutorService downloadMainExecutor = Executors.newSingleThreadExecutor(r -> {
        Thread t = new Thread(r, "local-download-main");
        t.setDaemon(false);
        return t;
    });

    /**
     * 下载器服务
     * 使用 volatile 关键字修饰 chunkDownloader，确保多线程环境下的可见性
     */
    private volatile ChunkDownloader chunkDownloader;

    @PostConstruct
    public void myInit() {
        log.info("初始化本地缓存服务");
        ChunkDownloader.DownloadConfig config = new ChunkDownloader.DownloadConfig();
        ChunkDownloader.DownloadListener listener = new ChunkDownloader.DownloadListener() {
            @Override
            public void onProgress(FileItem fileItem, String outputFile, long downloaded, long total) {
                if (log.isDebugEnabled()) {
                    double progress = total > 0 ? downloaded * 100.0 / total : 0;
                    String msg = String.format("[下载中] %s -> %s: %.2f%%", fileItem.getUrl(), outputFile, progress);
                    log.debug(msg);
                }
            }

            @Override
            public void onComplete(FileItem fileItem, String outputFile) {
                log.warn("✅ 下载完成: {}, fileItem={}", outputFile, fileItem.getUrl());
                //补充一下文件信息
                if (FileItem.DATATYPE_OFFICEFILE == fileItem.getDataType()) {
                    try {
                        OfficeFile officeFile = officeFileServices.getById(fileItem.getFileId());
                        if (officeFile == null) {
                            log.warn("officefile 数据库中文件不存在: fileId={}", fileItem.getFileId());
                            return;
                        }
                        long fileSize = Files.size(Paths.get(outputFile));
                        officeFile.setSize(fileSize);
                        officeFile.setLocalFlag(OfficeFile.LOCAL_FLAG_YES);
                        officeFile.setUpdateTime(LocalDateTime.now());
                        officeFileServices.save(officeFile);
                    } catch (IOException e) {
                        log.error("office file获取文件大小失败或写入文件信息失败: file={}, error={}", outputFile, e.getMessage(), e);
                    }
                } else {
                    try {
                        OfficePdf officePdf = officePdfServices.getById(fileItem.getFileId());
                        if (officePdf == null) {
                            log.warn("pdf 数据库中文件不存在: fileId={}", fileItem.getFileId());
                            return;
                        }
                        long fileSize = Files.size(Paths.get(outputFile));
                        officePdf.setLocalFlag(OfficePdf.LOCAL_FLAG_YES);
                        officePdf.setSize(fileSize);
                        officePdf.setUpdateTime(LocalDateTime.now());
                        officePdfServices.save(officePdf);
                    }catch (IOException e){
                        log.error("pdf 获取文件大小失败或写入文件信息失败: file={}, error={}", outputFile, e.getMessage(), e);
                    }
                }
            }

            @Override
            public void onError(FileItem fileItem, String outputFile, Throwable e) {
                log.error("❌ 下载失败: url={}, output={}, error={}", fileItem.getUrl(), outputFile, e.getMessage(), e);
            }
        };
        chunkDownloader = new ChunkDownloader(config, listener);
        log.info("本地缓存服务初始化完成");
    }

    @PreDestroy
    public void myDestroy() {
        log.info("关闭本地缓存服务");
        downloadMainExecutor.shutdown();
        try {
            if (!downloadMainExecutor.awaitTermination(30, TimeUnit.SECONDS)) {
                downloadMainExecutor.shutdownNow();
                if (!downloadMainExecutor.awaitTermination(30, TimeUnit.SECONDS)) {
                    log.warn("下载主线程池未能正常关闭");
                }
            }
        } catch (InterruptedException e) {
            downloadMainExecutor.shutdownNow();
            Thread.currentThread().interrupt();
            log.error("关闭下载主线程池时被中断", e);
        }

        if (chunkDownloader != null) {
            chunkDownloader.close();
        }
        log.info("本地缓存服务已关闭");
    }

    public void downloadLocalCache(FileItem fileItem) {
        if (chunkDownloader == null) {
            log.error("下载服务未初始化，无法下载文件: {}", fileItem != null ? fileItem.getUrl() : "null");
            return;
        }

        if (fileItem == null) {
            log.warn("尝试下载空的FileItem");
            return;
        }

        if (fileItem.getUrl() == null || fileItem.getUrl().isEmpty()) {
            log.warn("尝试下载URL为空的文件");
            return;
        }

        downloadMainExecutor.execute(() -> {
            try {
                Path path = Paths.get(fileItem.getLocalPath());
                if (path == null) {
                    log.error("无法生成本地文件路径: fileItem={}", fileItem);
                    return;
                }
                String outputPath = path.toAbsolutePath().toString();
                log.info("开始下载文件: {} -> {}", fileItem.getUrl(), outputPath);
                chunkDownloader.downloadFile(fileItem, outputPath);
            } catch (Exception e) {
                log.error("下载过程中发生异常: fileItem={}", fileItem, e);
            }
        });
    }

    /**
     * 是否下载中
     *
     * @param url 文件URL
     * @return 是否正在下载
     */
    public boolean isDownloading(String url) {
        if (chunkDownloader == null) {
            log.warn("下载服务未初始化，无法检查下载状态");
            return false;
        }

        if (url == null || url.isEmpty()) {
            return false;
        }

        return chunkDownloader.isDownloading(url);
    }
}